/*
 * Simple test file for cxxomfort
 * When compiled and run, 
 * this will generate a sequence of random numbers and filter it 
 * according to some criteria.
 * 
 * Interfaces tested in this example:
 * 
 * * algorithms (find_if, transform, cxxomfort:find_last_if)
 * * bind
 * * cxxomfort:fixed_vector
 * * cxxomfort:seq_
 * * cxxomfort:CXXO_FOREACH
 * * cxxomfort:constant_iterator
 * * cxxomfort:transparent_functional
 * 
 * A list of SIZ1 numbers will be generated, with type 'uint16_t'. 
 * The first and last numbers greater than LIM1 will be selected as pivots, if any.
 * Then, all positions in the list between the first and last found 
 * will be reduced modulo LIM2 via bind() and the std::modulus() transparent functor.
 * 
 * This and other examples assume cxxomfort is installed in 
 * include library path; if otherwise, compile with 
 * -I /path/to/cxxomfort .
 */

#include <cxxomfort/cxxomfort.hpp>
#include <cxxomfort/library/fixed_vector.hpp>
#include <cxxomfort/library/foreach.hpp>
#include <cxxomfort/library/iteratorfn.hpp>
#include <cxxomfort/library/algorithmfn.hpp>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <forward_list>
#include <algorithm>

const unsigned SIZ1 = 400;
const unsigned LIM1 = 19999;
const unsigned LIM2 = 100;
typedef uint16_t TT;
typedef cxxomfort::fixed_vector<TT> seq1_t_TT;
typedef std::vector<TT> seq2_t_TT;

template <typename Seq, typename S>
void outp_sequence (Seq const& ss, S& os);

int main () {
    using namespace std;
    cxxomfort::output_info(cout);
    cout<< endl;

    // A list of SIZ1 numbers will be generated, with type 'uint16_t'.
    cxxomfort::fixed_vector<TT> origin(SIZ1);
#if (CXXOMFORT_COMPILER_ID == CXXO_VALUE_COMPILER_GCC)
    srand48( time(0) );
    generate (begin(origin), end(origin), mrand48);
#else
    srand( time(0) );
    generate (begin(origin), end(origin), rand);
#endif
    
    outp_sequence(origin, cout);
    cout<< " -end of sequence."<< endl;
    
    // The first and last numbers greater than LIM1 will be selected as pivots, if any.
    cxxomfort::fixed_vector<TT>::iterator findth = find_if(begin(origin), end(origin), 
        bind(greater<void>(), placeholders::_1, LIM1));

    if (findth == end(origin)) {
        cout<< "No element in {origin} fulfills threshold 'x>"<< LIM1<< "'."<< endl;
        exit(0);
    }
    cout<< "first larger: "<< *findth<< endl;
    
    using cxxomfort::algorithm::find_last_if;
    cxxomfort::fixed_vector<TT>::iterator findlast = find_last_if(findth, end(origin), 
        bind(greater<void>(), placeholders::_1, LIM1));
    cout<< "last larger: "<< *findlast<< endl;
    if (findlast != end(origin)) ++findlast; // transform requires the "after the end" of range.

    // Then, all positions in the list between the first and last found 
    // will be reduced modulo LIM2 via bind() and the std::modulus() transparent functor.
    cout<< "Filtering numbers larger than "<< LIM1<< " to be % "<< LIM2<< "."<< endl;
    const uint16_t vlim2 = LIM2;
    typedef cxxomfort::iterator::fake_iterator<uint16_t> CIter_t;
    CIter_t clim2 (vlim2);
    transform(findth, findlast, clim2, findth
    , bind(std::modulus<void>(), placeholders::_1, placeholders::_2) );
    cout<< endl;
    
    outp_sequence(origin, cout);
    cout<< " -end of sequence."<< endl;
    cout<< endl;


}

template <typename Seq, typename S>
void outp_sequence (Seq const& ss, S& os) {
    CXXO_FOREACH( typename Seq::value_type const& x, ss) {
        os<< x<< ", ";
    }
}

